/*
 * 版权所有 (C) 2015 知启蒙(ZHIQIM) 保留所有权利。[遇见知启蒙，邂逅框架梦，本文采用木兰宽松许可证第2版]
 * 
 * https://zhiqim.org/project/zhiqim_kit/zhiqim_git.htm
 *
 * ZhiqimGit is licensed under Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of Mulan PSL v2 at:
 *          http://license.coscl.org.cn/MulanPSL2
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PSL v2 for more details.
 */
package org.zhiqim.git.command;

import java.io.IOException;
import java.util.LinkedList;
import java.util.List;

import org.zhiqim.git.Git;
import org.zhiqim.git.GitCommand;
import org.zhiqim.git.GitWalker;
import org.zhiqim.git.objer.ObjectWriter;
import org.zhiqim.git.objer.model.Commit;
import org.zhiqim.git.objer.model.PersonIdent;
import org.zhiqim.git.objer.objectid.ObjectId;
import org.zhiqim.git.objer.objectid.RevCommit;
import org.zhiqim.git.objer.objectid.RevTree;
import org.zhiqim.git.refer.RefUpdateResult;
import org.zhiqim.git.refer.RefUpdater;


/**
 * 提交命令<br>
 * http://www.kernel.org/pub/software/scm/git/docs/git-commit.html<br><br>
 *
 * @version v1.0.0 @author zouzhigang 2017-4-12 新建与整理
 */
public class CommitCommand extends GitCommand<RevCommit>
{
    private PersonIdent author;
    private PersonIdent committer;
    private String message;
    private List<ObjectId> parents = new LinkedList<ObjectId>();
    private boolean isLog;

    public CommitCommand(Git git)
    {
        super(git);
    }
    
    /******************************************************************************/
    //设置参数
    /******************************************************************************/

    public CommitCommand setMessage(String message)
    {
        this.message = message;
        return this;
    }

    public CommitCommand setCommitter(PersonIdent committer)
    {
        this.committer = committer;
        return this;
    }

    public CommitCommand setCommitter(String name, String email)
    {
        return setCommitter(new PersonIdent(name, email));
    }

    public CommitCommand setAuthor(PersonIdent author)
    {
        this.author = author;
        return this;
    }

    public CommitCommand setAuthor(String name, String email)
    {
        return setAuthor(new PersonIdent(name, email));
    }
    
    public CommitCommand setLog(boolean isLog)
    {
        this.isLog = isLog;
        return this;
    }
    
    /******************************************************************************/
    //检查&调用
    /******************************************************************************/

    protected void preprocess()
    {
        if (committer == null)
            committer = new PersonIdent(git);
        if (author == null)
            author = committer;
    }
    
    protected RevCommit execute() throws Exception
    {
        ObjectWriter writer = new ObjectWriter(git);
        
        try
        {
            ObjectId treeId = null;
            RevCommit headCommit = git.resolve(HEAD, RevCommit.class);
            if (headCommit == null)
            {//第一次提交，树内容为空
                treeId = writer.writeTree(new byte[0]);
            }
            else
            {//取上次提交的树
                RevTree tree = git.resolve(headCommit, RevTree.class);
                treeId = writer.writeTree(tree.getContent());
                parents.add(headCommit);
            }
            
            //写入一个提交对象
            Commit commit = new Commit();
            commit.setTree(treeId);
            commit.setParentIds(parents);
            commit.setAuthor(author);
            commit.setCommitter(committer);
            commit.setMessage(message);
            
            ObjectId commitId = writer.writeCommit(commit);

            //更新到引用管理器
            RevCommit revCommit = new GitWalker(git).parseCommit(commitId);
            RefUpdater updater = git.newUpdater(HEAD);
            updater.setNewObjectId(commitId);
            if (isLog)
                updater.setRefLogMessage("提交: " + revCommit.getShortMessage(), false);
            else
                updater.disableRefLog();
            
            updater.setExpectedOldObjectId(headCommit);
            RefUpdateResult rc = updater.update();
            switch (rc)
            {
            case NEW:
            case FAST_FORWARD:
                return revCommit;
            case REJECTED:
            case LOCK_FAILURE:
                throw new IOException("锁定文件时失败");
            default:
                throw new IOException("更新引用时失败");
            }
        }
        catch (IOException e)
        {
            throw new IOException("更新时失败");
        }
    }
    
    public RevCommit newCommit() throws IOException
    {
        ObjectWriter writer = new ObjectWriter(git);
        
        ObjectId treeId = null;
        RevCommit headCommit = git.resolve(HEAD, RevCommit.class);
        if (headCommit == null)
        {//第一次提交，树内容为空
            treeId = writer.writeTree(new byte[0]);
        }
        else
        {//取上次提交的树
            RevTree tree = git.resolve(headCommit, RevTree.class);
            treeId = writer.writeTree(tree.getContent());
            parents.add(headCommit);
        }
        
        //写入一个提交对象
        Commit commit = new Commit();
        commit.setTree(treeId);
        commit.setParentIds(parents);
        commit.setAuthor(author);
        commit.setCommitter(committer);
        commit.setMessage(message);
        
        ObjectId commitId = writer.writeCommit(commit);
        return new GitWalker(git).parseCommit(commitId);
    }
}
